package com.soa.zuul.filter;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.soa.zuul.entity.GatewayService;
import com.soa.zuul.entity.GatewayUser;
import com.soa.zuul.entity.GatewayUserServiceAuth;
import com.soa.zuul.service.FeignLogService;
import com.soa.zuul.service.UserAuthService;
import com.soa.zuul.util.CodeMsg;
import com.soa.zuul.util.Constant;
import com.soa.zuul.util.Json;
import com.soa.zuul.util.RequestUtil;

/**
 * URL认证、授权验证过滤器
 * @author zheng
 *
 */
public class UrlAuthFilter extends ZuulFilter {
	public final static Logger logger = LoggerFactory.getLogger(UrlAuthFilter.class);
	UserAuthService userAuthService;
	FeignLogService feignLogService;
	public UrlAuthFilter(UserAuthService userAuthService,FeignLogService feignLogService) {
		this.userAuthService=userAuthService;
		this.feignLogService =feignLogService;
	}

	/**
	 * 过滤器的具体逻辑
	 *
	 * 通过ctx.setSendZuulResponse(false)令zuul过滤该请求，不对其进行路由，
	 * 通过ctx.setResponseStatusCode(401)设置了其返回的错误码
	 * 通过ctx.setResponseBody(body)对返回body内容进行编辑等。
	 * 中文乱码：ctx.getResponse().setContentType("text/html;charset=UTF-8");
	 * 
	 * @return
	 */
	@Override
	public Object run() {
		CodeMsg codeMsg = CodeMsg.SUCCESS;
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String requestURI = request.getRequestURI();
        GatewayService gatewayService=(GatewayService)ctx.get("gatewayService");
        String access_token = (String)ctx.get("access_token");
        if(gatewayService!=null){
        	 //服务禁用
        	if (Constant.stateIsNo.equals(gatewayService.getState())) {
    			codeMsg = CodeMsg.SERVICE_STATE_ERROR;
    			feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseError(codeMsg, ctx))) ;
    			return null;
    		}
        	//如果存在url的配置则AppAuthFilter中的部分逻辑不执行
        	ctx.set("isUrlAuth",true);
        	//如果配置url需要权限验证
            if(Constant.IsAuthYes.equals(gatewayService.getIsNeedAuth())){
            	 GatewayUser gatewayUser=(GatewayUser)ctx.get("gatewayUser");
            	 //找不到token
            	 if(access_token==null){
            		codeMsg = CodeMsg.NONE_KEY;
            		feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseError(codeMsg, ctx))) ;
        			return null;
            	 }
            	 //token查不到用户
            	 if(gatewayUser==null){
            		 codeMsg = CodeMsg.ERROR_KEY;
            		 feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseError(codeMsg, ctx))) ;
         			return null;
            	 }
            	 //用户状态为禁用
         		if (Constant.stateIsNo.equals(gatewayUser.getState())) {
        			codeMsg = CodeMsg.USER_ERROR;
        			feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseError(codeMsg, ctx))) ;
        			return null;
        		}
            	 GatewayUserServiceAuth gatewayUserServiceAuth = userAuthService.getUserServiceAuthByKey(gatewayService.getPath(), gatewayUser.getKey());
            	// 权限验证
         		if (gatewayUserServiceAuth == null) {
         			codeMsg = CodeMsg.MUST_AUTH;
         			feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseError(codeMsg, ctx))) ;
        			return null;
         		}
         		 logger.info(requestURI+"   URL权限验证通过");
            }else{
         	   logger.info(requestURI+"   URL匿名调用");
            }
        }
		return null;
	}

	/**
	 * 返回一个boolean类型来判断该过滤器是否要执行，返回true，则过滤器生效
	 * 
	 * @return
	 */
	@Override
	public boolean shouldFilter() {
		 RequestContext ctx = RequestContext.getCurrentContext();
		 if(ctx.get("isSuccess")==null) return false;
		 return (boolean) ctx.get("isSuccess");//
	}


	@Override
	public int filterOrder() {
		return 30; // 过滤器的优先级
	}

	/**
	 * 返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型，具体如下： pre：可以在请求被路由之前调用
	 * routing：在路由请求时候被调用 post：在routing和error过滤器之后被调用 error：处理请求时发生错误时被调用
	 * 
	 * @return
	 */
	@Override
	public String filterType() {
		return "pre";
	}

}
